package com.xiangxue.nestedscroll.e_perfect_nestedscroll;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.RecyclerView;

import com.xiangxue.common.fragment.NestedLogRecyclerView;
import com.xiangxue.common.utils.FlingHelper;

public class NestedScrollLayout extends NestedScrollView {
    private View topView;
    private ViewGroup contentView;
    private static final String TAG = "NestedScrollLayout";

    public NestedScrollLayout(Context context) {
        this(context, null);
        init();
    }

    public NestedScrollLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
        init();
    }

    public NestedScrollLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
        init();
    }

    public NestedScrollLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private FlingHelper mFlingHelper;

    int totalDy = 0;
    /**
     * 用于判断RecyclerView是否在fling
     */
    boolean isStartFling = false;
    /**
     * 记录当前滑动的y轴加速度
     */
    private int velocityY = 0;

    private void init() {
        mFlingHelper = new FlingHelper(getContext());//惯性帮助者,即速度帮助者
        setOnScrollChangeListener(new View.OnScrollChangeListener() {//滑动监听者
            @Override
            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {//滑动监听事件,此事件会多次回调
                Log.i(TAG, "scrollY"+scrollY);
                if (isStartFling) {
                    totalDy = 0;
                    isStartFling = false;
                }
                if (scrollY == 0) {
                    Log.i(TAG, "TOP SCROLL");
                   // refreshLayout.setEnabled(true);
                }
                /*
                *getChildAt(0).getMeasuredHeight()是NestedScrollLayout的第一个元素的高度,即LinearLayout的高度
                *v.getMeasuredHeight()是NestedScrollLayout的高度
                *又因为LinearLayout的高度等于FixedDataScrollDisabledRecyclerView+contentView(需要吸顶的布局,contentView = (ViewGroup) ((ViewGroup) getChildAt(0)).getChildAt(1))
                * 吸顶的布局高度又等于NestedScrollLayout
                * 所以(getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())=topView的高度(topView = ((ViewGroup) getChildAt(0)).getChildAt(0))
                * scrollY == (getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())就说明当前滑动的坐标(这个坐标是指当前view相对于本身的坐标,不是相对屏幕的,以自己为原点在屏幕上滑动了多远)等于topView的距离,就把剩下的滑动距离给到子view去滑动
                * */
                if (scrollY == (getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) {
                    Log.i(TAG, "BOTTOM SCROLL");
                    dispatchChildFling();
                }
                //在RecyclerView fling情况下，记录当前RecyclerView在y轴的偏移
                totalDy += scrollY - oldScrollY;
            }
        });
    }

    private void dispatchChildFling() {//分发给孩子的惯性,即速度
        if (velocityY != 0) {
            Double splineFlingDistance = mFlingHelper.getSplineFlingDistance(velocityY);//根据速度算出距离,算出这个速度可以滑动多少距离
            if (splineFlingDistance > totalDy) {//如果可以滑动的距离大于已经滑动的距离,那么就给
                childFling(mFlingHelper.getVelocityByDistance(splineFlingDistance - Double.valueOf(totalDy)));
            }
        }
        totalDy = 0;
        velocityY = 0;
    }

    private void childFling(int velY) {//让孩子惯性移动
        RecyclerView childRecyclerView = getChildRecyclerView(contentView);
        if (childRecyclerView != null) {
            childRecyclerView.fling(0, velY);
        }
    }

    @Override
    public void fling(int velocityY) {//惯性事件,系统会提供一个初始化速度
        super.fling(velocityY);
        if (velocityY <= 0) {
            this.velocityY = 0;
        } else {
            isStartFling = true;
            this.velocityY = velocityY;//设置速度初始值
        }
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        topView = ((ViewGroup) getChildAt(0)).getChildAt(0);//获取第一个孩子的第1个元素,这里就是FixedDataScrollDisabledRecyclerView控件
        contentView = (ViewGroup) ((ViewGroup) getChildAt(0)).getChildAt(1);//获取第一个孩子的第二个元素,这里就是LinearLayout布局
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 调整contentView的高度为父容器高度，使之填充布局，避免父容器滚动后出现空白
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        ViewGroup.LayoutParams lp = contentView.getLayoutParams();

       /* 将LinearLayout布局的高度设置为本View的高度,而本view就是NestedScrollLayout的高度,通过查看源码得知,NestedScrollLayout高度就是他的第一个元素的高度,即match_parent填充屏幕,
          这样就能设置table+recyclerView的高度了,从而实现table吸顶效果*/
        lp.height = getMeasuredHeight();
        contentView.setLayoutParams(lp);
    }

    /**
     *
     * 父控件处理滑动控件,当子控件收到滑动事件的时候会调用父控件的此方法,看父控件怎么处理滑动事件
     * @param target    产生滑动事件的view
     * @param dx  本次x轴的滑动事件距离
     * @param dy  本次y轴的滑动事件距离
     * @param consumed 数组,consumed[0]的值表示父控件消耗了多少x轴距离的滑动事件,consumed[1]的值表示父控件消耗了多少y轴距离的滑动事件
     * @param type
     */
    @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        Log.i("NestedScrollLayout", getScrollY()+"::onNestedPreScroll::"+topView.getMeasuredHeight());
        // 向上滑动。若当前topview可见，需要将topview滑动至不可见
        boolean hideTop = dy > 0 && getScrollY() < topView.getMeasuredHeight();//getScrollY() < topView.getMeasuredHeight()表示当前ScrollView滑动的距离小于topView的高度,即topView还可见
        if (hideTop) {//如果可见
            scrollBy(0, dy);//y轴移动dy距离
            consumed[1] = dy;//告诉子控件我消耗了这么长的距离
        }
    }

    private RecyclerView getChildRecyclerView(ViewGroup viewGroup) {
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View view = viewGroup.getChildAt(i);
            if (view instanceof RecyclerView && view.getClass() == NestedLogRecyclerView.class) {
                return (RecyclerView) viewGroup.getChildAt(i);
            } else if (viewGroup.getChildAt(i) instanceof ViewGroup) {
                ViewGroup childRecyclerView = getChildRecyclerView((ViewGroup) viewGroup.getChildAt(i));
                if (childRecyclerView instanceof RecyclerView) {
                    return (RecyclerView) childRecyclerView;
                }
            }
            continue;
        }
        return null;
    }

}
